#       main.py
#       
#       Copyright 2010 Alexey Zotov <alexey.zotov@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

# -*- coding: utf8 -*-

import commands
import datetime
import logging
import os
import shutil
import urllib

from PyQt4 import QtCore
from PyQt4.QtCore import Qt
from PyQt4 import QtGui
from PyKDE4 import plasmascript
from PyKDE4.plasma import Plasma
from PyKDE4.kio import KIO
from PyKDE4.kdecore import KGlobal, KComponentData, i18n, KUrl
from PyKDE4.kdeui import KIcon, KNotification

import logger
import api_v1

try:
    import duplicates
except ImportError:
    DUPLICATES = False
else:
    DUPLICATES = True

from config import Config
from config_dialog import ConfigDialog
from random_wallpaper_dialog import RandomWallpaperDialog
from last_wallpaper_dialog import LastWallpaperDialog
from new_wallpaper_dialog import NewWallpaperDialog
from add_url_dialog import AddUrlDialog
from results_dialog import ResultsDialog
from wallpaper_info_dialog import WallpaperInfoDialog
from result_menu import ResultMenu
from send_bad_urls_dialog import SendBadUrlsDialog
from choice_duplicates_dialog import ChoiceDuplicatesDialog

class NewWallpaper(plasmascript.Applet):
    def __init__(self, parent, args=None):
        plasmascript.Applet.__init__(self, parent)
        
    @logger.log_exc
    def init(self):
        self.package_path = unicode(self.package().path())
        self.kdedir = unicode(KGlobal.dirs().localkdedir())
        
        self.setHasConfigurationInterface(True)
        self.setAspectRatioMode(Plasma.Square)

        layout = QtGui.QGraphicsLinearLayout(self.applet)
        self.setLayout(layout)
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().setSpacing(0)
        self.layout().setOrientation(Qt.Horizontal)

        self.icon = Plasma.IconWidget()
        self.icon.clicked.connect(self.icon_clicked)
        
        self.qicon = QtGui.QIcon(os.path.join(
            self.package_path,
            'contents','icons','new-wallpaper.svg'
        ))
        self.qicon_broken = QtGui.QIcon(os.path.join(
            self.package_path,
            'contents','icons','new-wallpaper-broken.svg'
        ))
        self.qicon_duplicate = QtGui.QIcon(os.path.join(
            self.package_path,
            'contents','icons','new-wallpaper-duplicate.svg'
        ))
        self.icon.setIcon(self.qicon)
        self.layout().addItem(self.icon)

        self.busy_counter = 0
        self.busy = Plasma.BusyWidget()
        self.busy.setVisible(False)

        corona = self.containment().corona()
        self.screen_containment = corona.containmentForScreen(
            self.containment().screen()
        )

        self.install_mo(
            unicode(KGlobal.locale().language())
        )
        KGlobal.locale().insertCatalog('new-wallpaper')

        self.install_icon()
        self.install_notifyrc()
        
        self.action_random_wallpaper = QtGui.QAction(
            i18n('Random wallpaper'), self)
        self.action_random_wallpaper.triggered.connect(
            self.random_wallpaper_request)
        self.action_last_wallpaper = QtGui.QAction(
            i18n('Last wallpaper'), self)
        self.action_last_wallpaper.triggered.connect(
            self.last_wallpaper_request)
        self.action_new_wallpaper = QtGui.QAction(
            i18n('New wallpaper'), self)
        self.action_new_wallpaper.triggered.connect(
            self.new_wallpaper_request)

        self.action_add_url = QtGui.QAction(
            i18n('Add url'), self)
        self.action_add_url.triggered.connect(
            self.add_url_request)

        self.action_force_scheduled = QtGui.QAction(
            i18n('Force scheduled request'), self)
        self.action_force_scheduled.triggered.connect(
            self.force_scheduled_request)

        self.action_last_set_wallpaper = QtGui.QAction(
            i18n('The last set wallpaper'), self)
        self.action_last_set_wallpaper.triggered.connect(
            self.last_set_wallpaper_triggered)
        self.action_last_set_wallpaper.setEnabled(False)

        self.action_send_bad_urls = QtGui.QAction(
            i18n('Send bad urls'), self)
        self.action_send_bad_urls.triggered.connect(
            self.send_bad_urls_triggered)
        self.action_send_bad_urls.setEnabled(False)

        self.action_show_duplicates = QtGui.QAction(
            i18n('Show duplicates'), self)
        self.action_show_duplicates.triggered.connect(
            self.show_duplicates_triggered)
        self.action_show_duplicates.setEnabled(False)
        
        homedir = os.path.expanduser('~')
        xdg_config = os.getenv(
            'XDG_CONFIG_HOME',
            os.path.join(homedir, '.config')
        )
        self.appdir = os.path.join(xdg_config, 'new-wallpaper')
        self.wallsdir = os.path.join(self.appdir, 'wallpapers')
        self.thumbsdir = os.path.join(self.appdir, 'thumbs')
        for path in (xdg_config, self.appdir, self.wallsdir, self.thumbsdir):
            if not os.path.isdir(path):
                os.mkdir(path)

        self.log_file = os.path.join(self.appdir, 'new-wallpaper.log')
        self.logger = logging.getLogger('new-wallpaper')
        self.logger.setLevel(logging.DEBUG)
        handler = logging.FileHandler(self.log_file)
        handler.setLevel(logging.DEBUG)
        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
        handler.setFormatter(formatter)
        self.logger.addHandler(handler)
            
        self.settings = {}
        self.cfg = Config(self.appdir)
        
        self.settings_read_bool('auth/anonymous', True)
        self.settings_read_string('auth/userid')
        self.settings_read_string('auth/password')
        self.settings_read_bool('auth/use_ssl')

        self.settings_read_bool('random_wallpaper/ask_settings', True)
        self.settings_read_int('random_wallpaper/count', 1)
        self.settings_read_string('random_wallpaper/resolutions')
        self.settings_read_string('random_wallpaper/tags')
        self.settings_read_string('random_wallpaper/notags')
        self.settings_read_bool('random_wallpaper/useronly')
        self.settings_read_bool('random_wallpaper/set_wallpaper', True)

        self.settings_read_bool('last_wallpaper/ask_settings', True)
        self.settings_read_int('last_wallpaper/count', 1)
        self.settings_read_bool('last_wallpaper/set_wallpaper', True)

        self.settings_read_bool('new_wallpaper/ask_settings', True)
        self.settings_read_int('new_wallpaper/count', 1)
        self.settings_read_float('new_wallpaper/weight', 1.0)
        self.settings_read_bool('new_wallpaper/set_wallpaper', True)

        self.settings_read_bool('schedule/enabled')
        self.settings_read_int('schedule/schedule', 24)
        self.settings_read_string('schedule/request', 'random_wallpaper')

        self.settings_read_int('scheduled_random_wallpaper/count', 1)
        self.settings_read_string('scheduled_random_wallpaper/resolutions')
        self.settings_read_string('scheduled_random_wallpaper/tags')
        self.settings_read_string('scheduled_random_wallpaper/notags')
        self.settings_read_bool('scheduled_random_wallpaper/useronly')
        self.settings_read_bool('scheduled_random_wallpaper/set_wallpaper', True)

        self.settings_read_int('scheduled_last_wallpaper/count', 1)
        self.settings_read_bool('scheduled_last_wallpaper/set_wallpaper', True)

        self.settings_read_int('scheduled_new_wallpaper/count', 1)
        self.settings_read_float('scheduled_new_wallpaper/weight', 1.0)
        self.settings_read_bool('scheduled_new_wallpaper/set_wallpaper', True)

        self.settings_read_string('icon/action', 'do_nothing')

        self.settings_read_int('results/user_opacity', 80)
        self.settings_read_bool('results/user_frame')
        self.settings_read_string('results/user_color', '#000000')

        self.settings_read_int('results/new_opacity', 100)
        self.settings_read_bool('results/new_frame', True)
        self.settings_read_string('results/new_color', '#00FF00')

        self.settings_read_int('results/bad_urls_opacity', 100)
        self.settings_read_bool('results/bad_urls_frame', True)
        self.settings_read_string('results/bad_urls_color', '#FF0000')

        self.settings_read_int('results/cached_opacity', 100)
        self.settings_read_bool('results/cached_frame', True)
        self.settings_read_string('results/cached_color', '#FFFF00')

        self.settings_read_bool('search_for_duplicates/enabled', True)
        self.settings_read_int('search_for_duplicates/interval', 10)
        self.settings_read_bool('search_for_duplicates/limited', True)
        self.settings_read_int('search_for_duplicates/limit', 100)
        self.settings_read_float('search_for_duplicates/mean', 10.0)
        self.settings_read_float('search_for_duplicates/stddev', 10.0)
        self.settings_read_bool('search_for_duplicates/send', True)

        self.action_last_wallpaper.setDisabled(
            self.settings['auth/anonymous'])
        self.action_new_wallpaper.setDisabled(
            self.settings['auth/anonymous'])
        self.action_add_url.setDisabled(
            self.settings['auth/anonymous'])

        self.action_force_scheduled.setEnabled(
            self.settings['schedule/enabled'])

        self.last_set_wallpaper = None
        self.notification = None
        self.bad_urls = []
        self.duplicates = []
        self.bad_urls_notified = False
        self.duplicates_notified = False
        self.choice_duplicates_dialog = None

        self.icon_actions = {
            'bad_urls': self.action_send_bad_urls,
            'duplicates': self.action_show_duplicates,
            'request_random_wallpaper': self.action_random_wallpaper,
            'request_last_wallpaper': self.action_last_wallpaper,
            'request_new_wallpaper': self.action_new_wallpaper,
            'add_url': self.action_add_url,
            'force_scheduled_request': self.action_force_scheduled
        }

        self.last_scheduled = self.cfg.read_date('last_scheduled/request')
        if self.settings['schedule/enabled']:
            self.scheduler_check()

        if DUPLICATES:
            self.get_potentials()
            
        self.timer_id = self.startTimer(60000)

    def install_mo(self, lang):
        mo_path = os.path.join(
            self.package_path,'contents','i18n',lang,'new-wallpaper.mo'
        )
        if not os.path.exists(mo_path):
            return
        dst_path = os.path.join(
            self.kdedir,'share','locale',lang,'LC_MESSAGES','new-wallpaper.mo'
        )
        if os.path.exists(dst_path):
            mo_stat = os.stat(mo_path)
            dst_stat = os.stat(dst_path)
            if mo_stat.st_mtime == dst_stat.st_mtime:
                return
        dirs = (
            os.path.join(self.kdedir,'share','locale'),
            os.path.join(self.kdedir,'share','locale',lang),
            os.path.join(self.kdedir,'share','locale',lang,'LC_MESSAGES')
        )
        for path in dirs:
            if not os.path.exists(path):
                os.mkdir(path)
        shutil.copy2(mo_path, dst_path)

    def install_icon(self):
        src_path = os.path.join(
            self.package_path, 'contents','icons','new-wallpaper.png')
        cmd = 'xdg-icon-resource install --size 128 %s' % src_path
        commands.getstatusoutput(cmd)

    def install_notifyrc(self):
        src_path = os.path.join(
            self.package_path,'contents','new-wallpaper.notifyrc')
        if not os.path.exists(src_path):
            return
        app_path = os.path.join(
            self.kdedir,'share','apps','new-wallpaper')
        dst_path = os.path.join(app_path, 'new-wallpaper.notifyrc')
        if os.path.exists(dst_path):
            src_stat = os.stat(src_path)
            dst_stat = os.stat(dst_path)
            if src_stat.st_mtime == dst_stat.st_mtime:
                return
        if not os.path.exists(app_path):
            os.mkdir(app_path)
        shutil.copy2(src_path, dst_path)

    def settings_read_bool(self, key, default=False):
        self.settings[key] = self.cfg.read_bool(key, default)

    def settings_read_string(self, key, default=''):
        self.settings[key] = self.cfg.read_string(key, default)

    def settings_read_int(self, key, default=0):
        self.settings[key] = self.cfg.read_int(key, default)

    def settings_read_float(self, key, default=0.0):
        self.settings[key] = self.cfg.read_float(key, default)
    
    def get_userid_and_password(self):
        if self.settings['auth/anonymous']:
            return None, '', False

        return (
            self.settings['auth/userid'],
            self.settings['auth/password'],
            self.settings['auth/use_ssl']
        )

    def set_plasma_wallpaper(self, result):
        if self.screen_containment.wallpaper():
            QtCore.QMetaObject.invokeMethod(
                self.screen_containment.wallpaper(),
                'setWallpaper',
                QtCore.Q_ARG(QtCore.QString, result['copypath'])
            )
            self.last_set_wallpaper = result
            self.action_last_set_wallpaper.setEnabled(True)
        else:
            self.notify_error(i18n('Unable to set plasma wallpaper'))

    def update_last_set_wallpaper(self, result):
        if not self.last_set_wallpaper:
            return
        if self.last_set_wallpaper['name'] != result['name']:
            return

        self.last_set_wallpaper.update(result)

    def set_busy(self, is_busy):
        if is_busy:
            if self.busy_counter == 0:
                while self.layout().count() > 0:
                    self.layout().removeAt(0)
                self.icon.setVisible(False)
                self.layout().addItem(self.busy)
                self.busy.setVisible(True)
            self.busy_counter += 1
        else:
            if self.busy_counter == 1:
                while self.layout().count() > 0:
                    self.layout().removeAt(0)
                self.busy.setVisible(False)
                self.layout().addItem(self.icon)
                self.icon.setVisible(True)
            if self.busy_counter > 0:
                self.busy_counter -= 1

    def show_notification(self, event, message):
        KNotification.event(
            event,
            message,
            QtGui.QPixmap(),
            None,
            KNotification.CloseOnTimeout,
            KComponentData(
                'new-wallpaper',
                'new-wallpaper',
                KComponentData.SkipMainComponentRegistration
            )
        )

    def notify(self, message):
        self.show_notification('notification', message)
        
    def notify_error(self, message):
        self.show_notification('error', message)

    def notify_response_error(self, response):
        if not response:
            return self.notify_error(i18n('No response'))
        if 'error' in response:
            return self.notify_error(response['error'])
        return self.notify_error(i18n('Bad response'))

    def notify_if_error_callback(self, job):
        self.set_busy(False)
        response = api_v1.parse_response(job)
        if not response or not response['success']:
            self.notify_response_error(response)

    def notify_bad_urls(self, all=False):
        self.notification = 'bad_urls'
        self.icon.setIcon(self.qicon_broken)
        self.action_send_bad_urls.setEnabled(True)

    @logger.log_exc
    def send_bad_urls_triggered(self, checked=False):
        self.notification = None
        self.icon.setIcon(self.qicon)
        self.action_send_bad_urls.setEnabled(False)
        urls_to_send = self.bad_urls[:5]
        self.bad_urls[:5] = []
        values = {
            'urls': urls_to_send
        }
        self.send_bad_urls_dialog = SendBadUrlsDialog(values)
        self.send_bad_urls_dialog.setWindowIcon(self.qicon)
        self.send_bad_urls_dialog.accepted.connect(
            self.send_bad_urls_dialog_accepted)
        self.send_bad_urls_dialog.show()

    @logger.log_exc
    def send_bad_urls_dialog_accepted(self):
        values = self.send_bad_urls_dialog.export_values()
        if values['urls']:
            self.request_send_bad_urls(values['urls'])
        if self.bad_urls:
            self.notify_bad_urls()

    def request_send_bad_urls(self, urls):
        @logger.log_exc
        def request_callback(job):
            self.set_busy(False)
            response = api_v1.parse_response(job)
            if response and response['success'] and 'result' in response:
                self.notify(response['result'])
            else:
                self.notify_response_error(response)

        userid, password, secure = self.get_userid_and_password()
        
        api_v1.send_bad_urls(
            request_callback,
            urls,
            userid,
            password,
            secure
        )
        self.set_busy(True)
    
    def notify_duplicates(self):
        self.notification = 'duplicates'
        self.icon.setIcon(self.qicon_duplicate)
        self.action_show_duplicates.setEnabled(True)

    @logger.log_exc
    def show_duplicates_triggered(self, checked=False):
        self.notification = None
        self.icon.setIcon(self.qicon)
        self.action_show_duplicates.setEnabled(False)
        duplicates = self.duplicates[:5]
        self.duplicates[:5] = []
        values = {
            'duplicates': duplicates
        }
        self.choice_duplicates_dialog = ChoiceDuplicatesDialog(
            self.thumbsdir, values)
        self.choice_duplicates_dialog.setWindowIcon(self.qicon)
        self.choice_duplicates_dialog.accepted.connect(
            self.choice_duplicates_dialog_accepted)
        self.choice_duplicates_dialog.rejected.connect(
            self.choice_duplicates_dialog_rejected)
        self.choice_duplicates_dialog.show()

    @logger.log_exc
    def choice_duplicates_dialog_accepted(self):
        choices = self.choice_duplicates_dialog.get_choices()
        duplicates.save_choices(self.appdir, choices)
        send_duplicates = not self.settings['auth/anonymous'] \
            and self.settings['search_for_duplicates/send']
        if send_duplicates:
            userid, password, secure = self.get_userid_and_password()
            for choice in choices:
                if not choice[4]:
                    continue
                original = choice[4] == 1 and choice[0] or choice[1]
                copy = choice[4] == 1 and choice[1] or choice[0]
                
                api_v1.send_duplicate(
                    self.notify_if_error_callback,
                    original,
                    copy,
                    userid,
                    password,
                    secure
                )
                self.set_busy(True)

        self.choice_duplicates_dialog_finished()

    @logger.log_exc
    def choice_duplicates_dialog_rejected(self):
        self.choice_duplicates_dialog_finished()
    
    def choice_duplicates_dialog_finished(self):
        self.choice_duplicates_dialog.deleteLater()
        self.choice_duplicates_dialog = None

        self.get_potentials()

    @logger.log_exc
    def icon_clicked(self):
        action = None
        if self.notification:
            action = self.icon_actions[self.notification]
        elif self.settings['icon/action'] in self.icon_actions:
            action = self.icon_actions[self.settings['icon/action']]
        if action and action.isEnabled():
            action.trigger()

    def set_wallpaper(self, result):
        @logger.log_exc
        def copy_callback(job):
            if not job.error():
                self.set_busy(False)
                if result['bad_urls']:
                    self.bad_urls.extend(result['bad_urls'])
                    if not self.settings['auth/anonymous']:
                        self.notify_bad_urls()
                return self.set_plasma_wallpaper(result)
            
            result['bad_urls'].append(result['urls'][result['url_index']])
            result['url_index'] += 1
            if result['url_index'] < len(result['urls']):
                job = KIO.file_copy(
                    KUrl(result['urls'][result['url_index']]),
                    KUrl('file://' + result['copypath']),
                    -1,
                    KIO.JobFlags(KIO.HideProgressInfo | KIO.Overwrite)
                )
                job.result.connect(copy_callback)
            else:
                self.set_busy(False)
                self.bad_urls.extend(result['bad_urls'])
                if self.settings['auth/anonymous']:
                    self.notify_error(i18n('All urls failed to download'))
                else:
                    self.notify_bad_urls(all=True)
        
        result['copypath'] = os.path.join(self.wallsdir, result['name'])
        if os.path.isfile(result['copypath']):
            return self.set_plasma_wallpaper(result)

        if not result['urls']:
            return self.notify_error(
                i18n('There are no urls for this wallpaper'))
        
        result['url_index'] = 0
        result['bad_urls'] = []
            
        job = KIO.file_copy(
            KUrl(result['urls'][0]),
            KUrl('file://' + result['copypath']),
            -1,
            KIO.JobFlags(KIO.HideProgressInfo | KIO.Overwrite)
        )
        job.result.connect(copy_callback)
        self.set_busy(True)

    def process_results(self, job, params, set_wallpaper=True, useronly=True,
        check_duplicates=True):

        @logger.log_exc
        def request_callback(job):
            self.set_busy(False)
            self.process_results(
                job,
                params,
                set_wallpaper,
                useronly,
                check_duplicates=False
            )                
        
        response = api_v1.parse_response(job)
        if not (response and response['success'] and 'results' in response):
            self.notify_response_error(response)
            return
        
        results = response['results']
        if not results:
            self.notify(i18n('Not returned any result'))
            return
        
        if DUPLICATES and check_duplicates:
            wallpapers = [result['name'] for result in results]
            originals = duplicates.get_originals(
                self.appdir,
                wallpapers,
                self.settings['search_for_duplicates/mean'],
                self.settings['search_for_duplicates/stddev']
            )

            if originals:
                to_delete = []
                for copy, original in originals.iteritems():
                    wallpapers.remove(copy)
                    if not original in wallpapers:
                        wallpapers.append(original)
                    else:
                        to_delete.append(copy)
                for copy in to_delete:
                    del originals[copy]
                if originals:
                    userid, password, secure = self.get_userid_and_password()
                    
                    api_v1.wallpapers_info(
                        request_callback,
                        wallpapers,
                        useronly,
                        userid,
                        password,
                        secure
                    )
                    self.set_busy(True)
                    return
                else:
                    results = [
                        result for result in results
                        if result['name'] in wallpapers
                    ]

        if DUPLICATES and 'nulls' in response:
            for wallpaper in response['nulls']:
                try:
                    os.unlink(os.path.join(self.thumbsdir,wallpaper))
                    duplicates.delete_status(self.appdir, wallpaper)
                except:
                    duplicates.set_invalid_status(self.appdir, wallpaper)
        
        if set_wallpaper:
            self.set_wallpaper(results[0])
        else:
            for result in results:
                filepath = os.path.join(self.wallsdir, result['name'])
                result['cached'] = os.path.isfile(filepath)
            
            self.results_dialog = ResultsDialog(
                params,
                self,
                results,
                WallpaperInfoDialog,
                ResultMenu
            )
            self.results_dialog.closed.connect(self.results_dialog_closed)
            self.results_dialog.show()

    @logger.log_exc
    def results_dialog_closed(self):
        self.results_dialog.deleteLater()
    
    @logger.log_exc
    def random_wallpaper_request(self, checked=False):
        if self.settings['random_wallpaper/ask_settings']:
            values = {}
            values['anonymous'] = self.settings['auth/anonymous']
            values['count'] = self.cfg.read_int(
                'last_random_wallpaper/count', 1)
            values['resolutions'] = self.cfg.read_string(
                'last_random_wallpaper/resolutions')
            values['tags'] = self.cfg.read_string(
                'last_random_wallpaper/tags')
            values['notags'] = self.cfg.read_string(
                'last_random_wallpaper/notags')
            values['useronly'] = self.cfg.read_bool(
                'last_random_wallpaper/useronly')
            values['set_wallpaper'] = self.cfg.read_bool(
                'last_random_wallpaper/set_wallpaper', True)
            self.random_wallpaper_dialog = RandomWallpaperDialog(values)
            self.random_wallpaper_dialog.setWindowIcon(self.qicon)
            self.random_wallpaper_dialog.accepted.connect(
                self.random_wallpaper_dialog_accepted)
            self.random_wallpaper_dialog.rejected.connect(
                self.random_wallpaper_dialog_rejected)
            self.random_wallpaper_dialog.show()
        else:
            self.request_random_wallpaper(
                self.settings['random_wallpaper/count'],
                self.settings['random_wallpaper/resolutions'],
                self.settings['random_wallpaper/tags'],
                self.settings['random_wallpaper/notags'],
                self.settings['random_wallpaper/useronly'],
                self.settings['random_wallpaper/set_wallpaper']
            )
    
    @logger.log_exc
    def random_wallpaper_dialog_accepted(self):
        values = self.random_wallpaper_dialog.export_values()
        self.cfg.write(
            'last_random_wallpaper/count', values['count'])
        self.cfg.write(
            'last_random_wallpaper/resolutions', values['resolutions'])
        self.cfg.write(
            'last_random_wallpaper/tags', values['tags'])
        self.cfg.write(
            'last_random_wallpaper/notags', values['notags'])
        self.cfg.write(
            'last_random_wallpaper/useronly', values['useronly'])
        self.cfg.write(
            'last_random_wallpaper/set_wallpaper', values['set_wallpaper'])
        self.cfg.sync()
        self.random_wallpaper_dialog.deleteLater()
        self.request_random_wallpaper(**values)
    
    @logger.log_exc
    def random_wallpaper_dialog_rejected(self):
        self.random_wallpaper_dialog.deleteLater()
    
    def request_random_wallpaper(self, count=1, resolutions=None, tags=None,
        notags=None, useronly=False, set_wallpaper=True):

        @logger.log_exc
        def request_callback(job):
            self.set_busy(False)
            self.process_results(
                job,
                {
                    'title': i18n('Random wallpaper'),
                    'method': self.request_random_wallpaper,
                    'args': [count, resolutions, tags, notags, useronly, set_wallpaper]
                },
                set_wallpaper,
                useronly
            )                
        
        userid, password, secure = self.get_userid_and_password()
        
        api_v1.random_wallpapers(
            request_callback,
            count,
            resolutions,
            tags,
            notags,
            useronly,
            userid,
            password,
            secure
        )
        self.set_busy(True)

    @logger.log_exc
    def last_wallpaper_request(self, checked=False):
        if self.settings['last_wallpaper/ask_settings']:
            values = {}
            values['count'] = self.cfg.read_int(
                'last_last_wallpaper/count', 1)
            values['set_wallpaper'] = self.cfg.read_bool(
                'last_last_wallpaper/set_wallpaper', True)
            self.last_wallpaper_dialog = LastWallpaperDialog(values)
            self.last_wallpaper_dialog.setWindowIcon(self.qicon)
            self.last_wallpaper_dialog.accepted.connect(
                self.last_wallpaper_dialog_accepted)
            self.last_wallpaper_dialog.rejected.connect(
                self.last_wallpaper_dialog_rejected)
            self.last_wallpaper_dialog.show()
        else:
            self.request_last_wallpaper(
                self.settings['last_wallpaper_count'],
                self.settings['last_wallpaper_set_wallpaper']
            )

    @logger.log_exc
    def last_wallpaper_dialog_accepted(self):
        values = self.last_wallpaper_dialog.export_values()
        self.cfg.write(
            'last_last_wallpaper/count', values['count'])
        self.cfg.write(
            'last_last_wallpaper/set_wallpaper', values['set_wallpaper'])
        self.cfg.sync()
        self.last_wallpaper_dialog.deleteLater()
        self.request_last_wallpaper(
            values['count'],
            values['set_wallpaper']
        )

    @logger.log_exc
    def last_wallpaper_dialog_rejected(self):
        self.last_wallpaper_dialog.deleteLater()

    def request_last_wallpaper(self, count=1, set_wallpaper=True):
        def request_callback(job):
            self.set_busy(False)
            self.process_results(
                job,
                {
                    'title': i18n('Last wallpaper'),
                    'method': self.request_last_wallpaper,
                    'args': [count, set_wallpaper]
                },
                set_wallpaper
            )                

        userid, password, secure = self.get_userid_and_password()
        
        api_v1.last_wallpapers(
            request_callback,
            count,
            userid,
            password,
            secure
        )
        self.set_busy(True)

    @logger.log_exc
    def new_wallpaper_request(self, checked=False):
        if self.settings['new_wallpaper/ask_settings']:
            values = {}
            values['count'] = self.cfg.read_int(
                'last_new_wallpaper/count', 1)
            values['weight'] = self.cfg.read_float(
                'last_new_wallpaper/weight', 1.0)
            values['set_wallpaper'] = self.cfg.read_bool(
                'last_new_wallpaper/set_wallpaper', True)
            self.new_wallpaper_dialog = NewWallpaperDialog(values)
            self.new_wallpaper_dialog.setWindowIcon(self.qicon)
            self.new_wallpaper_dialog.accepted.connect(
                self.new_wallpaper_dialog_accepted)
            self.new_wallpaper_dialog.rejected.connect(
                self.new_wallpaper_dialog_rejected)
            self.new_wallpaper_dialog.show()
        else:
            self.request_new_wallpaper(
                self.settings['new_wallpaper/count'],
                self.settings['new_wallpaper/weight'],
                self.settings['new_wallpaper/set_wallpaper']
            )

    @logger.log_exc
    def new_wallpaper_dialog_accepted(self):
        values = self.new_wallpaper_dialog.export_values()
        self.cfg.write(
            'last_new_wallpaper/count', values['count'])
        self.cfg.write(
            'last_new_wallpaper/weight', values['weight'])
        self.cfg.write(
            'last_new_wallpaper/set_wallpaper', values['set_wallpaper'])
        self.cfg.sync()
        self.new_wallpaper_dialog.deleteLater()
        self.request_new_wallpaper(
            values['count'],
            values['weight'],
            values['set_wallpaper']
        )

    @logger.log_exc
    def new_wallpaper_dialog_rejected(self):
        self.new_wallpaper_dialog.deleteLater()

    def request_new_wallpaper(self, count=1, weight=1.0, set_wallpaper=True):
        def request_callback(job):
            self.set_busy(False)
            self.process_results(
                job,
                {
                    'title': i18n('New wallpaper'),
                    'method': self.request_new_wallpaper,
                    'args': [count, weight, set_wallpaper]
                },
                set_wallpaper,
                useronly=False
            )                

        userid, password, secure = self.get_userid_and_password()
        
        api_v1.new_wallpapers(
            request_callback,
            count,
            weight,
            userid,
            password,
            secure
        )
        self.set_busy(True)
    
    @logger.log_exc
    def add_url_request(self, checked=False):
        values = {
            'xmpp': self.cfg.read_bool('last_add_url/xmpp')
        }
        self.add_url_dialog = AddUrlDialog(values)
        self.add_url_dialog.setWindowIcon(self.qicon)
        self.add_url_dialog.accepted.connect(self.add_url_dialog_accepted)
        self.add_url_dialog.rejected.connect(self.add_url_dialog_rejected)
        self.add_url_dialog.show()

    @logger.log_exc
    def add_url_dialog_accepted(self):
        values = self.add_url_dialog.export_values()
        self.cfg.write('last_add_url/xmpp', values['xmpp'])
        self.cfg.sync()
        self.add_url_dialog.deleteLater()
        self.request_add_url(values['url'], values['tags'], values['xmpp'])

    @logger.log_exc
    def add_url_dialog_rejected(self):
        self.add_url_dialog.deleteLater()

    def request_add_url(self, url, tags=None, xmpp=None):
        def request_callback(job):
            self.set_busy(False)
            response = api_v1.parse_response(job)
            if response and response['success'] and 'result' in response:
                self.notify(response['result'])
            else:
                self.notify_response_error(response)
        
        userid, password, secure = self.get_userid_and_password()
        
        api_v1.add_url(
            request_callback,
            url,
            userid,
            password,
            tags,
            xmpp,
            secure
        )
        self.set_busy(True)

    def request_add_wallpaper(self, wallpaper, tags):
        userid, password, secure = self.get_userid_and_password()
        
        api_v1.add_wallpaper(
            self.add_wallpaper_tags_callback,
            wallpaper,
            tags,
            userid,
            password,
            secure
        )
        self.set_busy(True)
        

    def request_add_tags(self, wallpaper, tags):
        userid, password, secure = self.get_userid_and_password()
        
        api_v1.add_tags(
            self.add_wallpaper_tags_callback,
            wallpaper,
            tags,
            userid,
            password,
            secure
        )
        self.set_busy(True)

    @logger.log_exc
    def add_wallpaper_tags_callback(self, job):
        self.set_busy(False)
        response = api_v1.parse_response(job)
        if response and response['success'] and 'result' in response:
            result = response['result']
            self.results_dialog.update_result(result)
            self.update_last_set_wallpaper(result)
            tags = result['user'] and result['user_tags'] or result['tags']
            message = '%s\n%s %s' % (
                result['name'],
                i18n('Top tags:'),
                ', '.join(tags)
            )
            self.notify(message)
        else:
            self.notify_response_error(response)

    def request_reject_wallpaper(self, wallpaper):
        @logger.log_exc
        def request_callback(job):
            self.set_busy(False)
            response = api_v1.parse_response(job)
            if not (response and response['success'] and 'result' in response):
                self.notify_response_error(response)
                return
            self.results_dialog.update_result(response['result'])
            self.update_last_set_wallpaper(response['result'])

        userid, password, secure = self.get_userid_and_password()
        
        api_v1.reject_wallpaper(
            request_callback,
            wallpaper,
            userid,
            password,
            secure
        )
        self.set_busy(True)

    @logger.log_exc
    def contextualActions(self):
        request_action = QtGui.QAction(i18n('Request'), self)
        request_menu = QtGui.QMenu(self.view())
        request_action.setMenu(request_menu)
        
        request_menu.addAction(self.action_random_wallpaper)
        request_menu.addAction(self.action_last_wallpaper)
        request_menu.addAction(self.action_new_wallpaper)
        
        return [
            request_action,
            self.action_add_url,
            self.action_force_scheduled,
            self.action_last_set_wallpaper,
            self.action_send_bad_urls,
            self.action_show_duplicates
        ]
    
    @logger.log_exc
    def showConfigurationInterface(self):
        self.config_dialog = ConfigDialog(self.settings, DUPLICATES)
        self.config_dialog.setWindowIcon(self.qicon)
        self.config_dialog.accepted.connect(self.configuration_accepted)
        self.config_dialog.rejected.connect(self.configuration_rejected)
        self.config_dialog.show()
        
    
    @logger.log_exc
    def configuration_accepted(self):
        settings = self.config_dialog.export_settings()
        self.settings.update(settings)

        for k, v in settings.iteritems():
            self.cfg.write(k, v)
        self.cfg.sync()
        
        self.config_dialog.deleteLater()

        self.action_last_wallpaper.setDisabled(
            self.settings['auth/anonymous'])
        self.action_new_wallpaper.setDisabled(
            self.settings['auth/anonymous'])
        self.action_add_url.setDisabled(
            self.settings['auth/anonymous'])

        self.action_force_scheduled.setEnabled(
            self.settings['schedule/enabled'])
    
    @logger.log_exc
    def configuration_rejected(self):
        self.config_dialog.deleteLater()

    def scheduler_request(self):
        if self.settings['schedule/request'] == 'random_wallpaper': 
            self.request_random_wallpaper(
                self.settings['scheduled_random_wallpaper/count'],
                self.settings['scheduled_random_wallpaper/resolutions'],
                self.settings['scheduled_random_wallpaper/tags'],
                self.settings['scheduled_random_wallpaper/notags'],
                self.settings['scheduled_random_wallpaper/useronly'],
                self.settings['scheduled_random_wallpaper/set_wallpaper']
            )
        elif self.settings['schedule/request'] == 'last_wallpaper': 
            self.request_last_wallpaper(
                self.settings['scheduled_last_wallpaper/count'],
                self.settings['scheduled_last_wallpaper/set_wallpaper']
            )
        elif self.settings['schedule/request'] == 'new_wallpaper':
            self.request_new_wallpaper(
                self.settings['scheduled_new_wallpaper/count'],
                self.settings['scheduled_new_wallpaper/weight'],
                self.settings['scheduled_new_wallpaper/set_wallpaper']
            )

    def scheduler_check(self, force=False):
        now = datetime.datetime.utcnow()
        scheduler_delta = datetime.timedelta(
            hours=self.settings['schedule/schedule'])
        delta = now - self.last_scheduled
        if force or delta > scheduler_delta:
            self.scheduler_request()
            if force:
                self.last_scheduled = now
            else:
                while self.last_scheduled < now:
                    self.last_scheduled += scheduler_delta
                self.last_scheduled -= scheduler_delta
            self.cfg.write_date('last_scheduled/request', self.last_scheduled)
            self.cfg.sync()

    @logger.log_exc
    def force_scheduled_request(self, checked=False):
        self.scheduler_check(force=True)

    @logger.log_exc
    def last_set_wallpaper_triggered(self, checked=False):
        self.last_set_wallpaper['thumbpath'] = os.path.join(
            self.thumbsdir, self.last_set_wallpaper['name'])

        if os.path.isfile(self.last_set_wallpaper['thumbpath']):
            self.show_last_set_wallpaper()
            return

        self.download_thumb(
            self.last_set_wallpaper['thumb'],
            self.last_set_wallpaper['thumbpath'],
            self.download_thumb_callback
        )
        self.set_busy(True)

    @logger.log_exc
    def download_thumb_callback(self, job):
        self.set_busy(False)
        if job.error():
            self.notify_error(i18n('Thumb downloading error'))
            return
        self.show_last_set_wallpaper()

    def download_thumb(self, thumb_url, path, callback):
        job = KIO.file_copy(
            KUrl(thumb_url),
            KUrl('file://%s' % path),
            -1,
            KIO.JobFlags(KIO.HideProgressInfo | KIO.Overwrite)
        )
        job.result.connect(callback)

    def show_last_set_wallpaper(self):
        self.wallpaper_info_dialog = WallpaperInfoDialog(
            self, self.last_set_wallpaper)
        self.wallpaper_info_dialog.accepted.connect(
            self.wallpaper_info_dialog_closed)
        self.wallpaper_info_dialog.rejected.connect(
            self.wallpaper_info_dialog_closed)
        self.wallpaper_info_dialog.show()

    @logger.log_exc
    def wallpaper_info_dialog_closed(self):
        self.wallpaper_info_dialog.deleteLater()

    def search_duplicates(self):
        last_image1 = self.cfg.read_string('search_for_duplicates/last_image1')
        last_image2 = self.cfg.read_string('search_for_duplicates/last_image2')
        
        last_pair = duplicates.find_potentials(
            self.appdir,
            self.settings['search_for_duplicates/mean'],
            self.settings['search_for_duplicates/stddev'],
            self.settings['search_for_duplicates/limited'] \
                and self.settings['search_for_duplicates/limit'],
            last_image1,
            last_image2,
            QtCore.QCoreApplication.processEvents
        )
        
        self.cfg.write('search_for_duplicates/last_image1', last_pair[0])
        self.cfg.write('search_for_duplicates/last_image2', last_pair[1])
        self.cfg.sync()
        
        self.get_potentials()

    def get_potentials(self):
        if self.choice_duplicates_dialog:
            return
        
        potentials = duplicates.get_potentials(
            self.appdir,
            self.settings['search_for_duplicates/mean'],
            self.settings['search_for_duplicates/stddev']
        )

        self.duplicates = list(set(self.duplicates + potentials))
        if self.duplicates:
            self.notify_duplicates()

    def search_duplicates_check(self):
        now = datetime.datetime.utcnow()
        search_duplicates_delta = datetime.timedelta(
            minutes=self.settings['search_for_duplicates/interval'])
        last_scheduled = self.cfg.read_date(
            'last_scheduled\search_for_duplicates')
        delta = now - last_scheduled
        if delta > search_duplicates_delta:
            self.search_duplicates()
            while last_scheduled < now:
                last_scheduled += search_duplicates_delta
            last_scheduled -= search_duplicates_delta
            self.cfg.write_date(
                'last_scheduled/search_for_duplicates',
                last_scheduled
            )
            self.cfg.sync()

    @logger.log_exc
    def timerEvent(self, event):
        plasmascript.Applet.timerEvent(self, event)
        if event.timerId() == self.timer_id:
            if self.settings['schedule/enabled']:
                self.scheduler_check()
            if DUPLICATES and self.settings['search_for_duplicates/enabled']:
                self.search_duplicates_check()

def CreateApplet(parent):
    return NewWallpaper(parent)
